/* eslint-disable no-loop-func */
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-await-in-loop */
const { arrayChunkOperation } = require('../../../../../utility');
const Excel = require('../../../adapter/excel');

class FileExcel extends Excel {
  async generate(data, outputPath) {
    // construct excel
    this.addSheet('sheet1');
    this.mergeCells('A1', 'B1');

    // style
    const leftBorder = {
      top: { style: 'thin' },
      left: { style: 'thin' },
      bottom: { style: 'thin' },
    };
    const rightBorder = {
      top: { style: 'thin' },
      right: { style: 'thin' },
      bottom: { style: 'thin' },
    };
    const boldWhiteFont = {
      name: 'Arial',
      bold: true,
      size: 12,
      color: { argb: 'FFFFFF' },
    };
    const boldBlackFont = {
      name: 'Arial',
      bold: true,
      size: 12,
      color: { argb: '000000' },
    };
    const nameSize12Font = { name: 'Arial', size: 12 };
    const nameSize14Font = { name: 'Arial', size: 14 };
    const defaultFill = { type: 'pattern', pattern: 'solid' };
    const leftAlignment = { vertical: 'middle', horizontal: 'left' };
    const middleAlignment = { vertical: 'middle', horizontal: 'center' };
    this.lastSheet.getColumn(1).width = 20;
    this.lastSheet.getColumn(2).width = 60;
    this.lastSheet.properties.defaultRowHeight = 25;

    // first line
    this.setCell('A1', {
      value: `【${data.fileName}】`,
      alignment: { vertical: 'middle', horizontal: 'left' },
      font: { ...nameSize14Font },
    });
    // rules content
    let currentLine = 3;
    for (const setElement of data.allRulesBySet) {
      for (const levelName of ['level1', 'level2', 'level3']) {
        for (const ruleElement of setElement.rules[levelName]) {
          this.mergeCells(`A${currentLine}`, `B${currentLine}`);
          let row = this.getRow(currentLine);
          row.getCell(1).value = `${setElement.ruleSetName} ${ruleElement.ruleCode}`;
          row.getCell(1).alignment = leftAlignment;
          row.getCell(1).font = {
            ...nameSize14Font,
            color: { argb: '000000' },
          };
          currentLine += 1;

          row = this.getRow(currentLine);
          row.getCell(1).value = `缺陷数量：${ruleElement.total}个`;
          row.getCell(1).alignment = leftAlignment;
          // level color
          const levelFill = {
            ...defaultFill,
          };
          if (levelName === 'level1') {
            levelFill.fgColor = { argb: 'cb3e36' };
          } else {
            levelFill.fgColor = {};
            levelFill.fgColor.argb = levelName === 'level3' ? '4dd5b3' : 'fdbb36';
          }
          row.getCell(1).fill = {
            ...defaultFill,
            fgColor: { argb: '87898b' },
          };
          row.getCell(1).font = boldWhiteFont;
          row.getCell(2).value = `${ruleElement.level}`;
          row.getCell(2).fill = levelFill;
          row.getCell(2).alignment = middleAlignment;
          row.getCell(2).font = boldWhiteFont;
          currentLine += 1;

          this.mergeCells(`A${currentLine}`, `B${currentLine}`);
          row = this.getRow(currentLine);
          row.getCell(1).value = `缺陷描述：${ruleElement.name}`;
          row.getCell(1).alignment = leftAlignment;
          row.getCell(1).fill = {
            ...defaultFill,
            fgColor: { argb: 'b9b8bb' },
          };
          row.getCell(1).font = boldBlackFont;
          currentLine += 2;

          // defects
          await arrayChunkOperation(ruleElement.defects, 20, (defectElement) => {
            row = this.getRow(currentLine);
            row.getCell(1).value = `缺陷${defectElement.index}`;
            row.getCell(1).alignment = leftAlignment;
            row.getCell(1).font = {
              ...nameSize14Font,
              bold: true,
              color: { argb: '000000' },
            };
            currentLine += 1;

            row = this.getRow(currentLine);
            row.getCell(1).value = '发生位置';
            row.getCell(1).alignment = leftAlignment;
            row.getCell(1).font = boldBlackFont;
            row.getCell(1).border = leftBorder;
            row.getCell(2).value = `${defectElement.filePath}`;
            row.getCell(2).alignment = leftAlignment;
            row.getCell(2).font = {
              ...nameSize12Font,
              color: { argb: '000000' },
            };
            row.getCell(2).border = rightBorder;
            currentLine += 1;

            row = this.getRow(currentLine);
            row.getCell(1).value = '起始位置';
            row.getCell(1).alignment = leftAlignment;
            row.getCell(1).font = boldBlackFont;
            row.getCell(1).border = leftBorder;
            row.getCell(2).value = `(${defectElement.locations.begin.line}, ${defectElement.locations.begin.column})`;
            row.getCell(2).alignment = leftAlignment;
            row.getCell(2).font = {
              ...nameSize12Font,
              color: { argb: '000000' },
            };
            row.getCell(2).border = rightBorder;
            currentLine += 1;

            row = this.getRow(currentLine);
            row.getCell(1).value = '终止位置';
            row.getCell(1).alignment = leftAlignment;
            row.getCell(1).font = boldBlackFont;
            row.getCell(1).border = leftBorder;
            row.getCell(2).value = `(${defectElement.locations.end.line}, ${defectElement.locations.end.column})`;
            row.getCell(2).alignment = leftAlignment;
            row.getCell(2).font = {
              ...nameSize12Font,
              color: { argb: '000000' },
            };
            row.getCell(2).border = rightBorder;
            currentLine += 1;

            // lines
            defectElement.lines.forEach((lineElement) => {
              row = this.getRow(currentLine);
              row.getCell(1).value = `${lineElement.line}`;
              row.getCell(1).alignment = middleAlignment;
              row.getCell(2).value = `${lineElement.content}`;
              row.getCell(2).alignment = leftAlignment;
              const lineFont = { ...nameSize12Font, color: { argb: '333333' } };
              if (lineElement.red) {
                lineFont.color.argb = 'fb0008';
                row.getCell(1).fill = {
                  ...defaultFill,
                  fgColor: { argb: 'e7e6e6' },
                };
                row.getCell(2).fill = {
                  ...defaultFill,
                  fgColor: { argb: 'e7e6e6' },
                };
              }
              row.getCell(1).font = lineFont;
              row.getCell(1).border = leftBorder;
              row.getCell(2).font = lineFont;
              row.getCell(2).border = rightBorder;
              currentLine += 1;
            });

            // status and description
            row = this.getRow(currentLine);
            row.getCell(1).value = '缺陷状态';
            row.getCell(1).alignment = leftAlignment;
            row.getCell(1).font = boldBlackFont;
            row.getCell(1).border = leftBorder;
            row.getCell(2).value = `${defectElement.status}`;
            row.getCell(2).alignment = leftAlignment;
            row.getCell(2).font = {
              ...nameSize12Font,
              color: { argb: '000000' },
            };
            row.getCell(2).border = rightBorder;
            currentLine += 1;

            row = this.getRow(currentLine);
            row.getCell(1).value = '信息说明';
            row.getCell(1).alignment = leftAlignment;
            row.getCell(1).font = boldBlackFont;
            row.getCell(1).border = leftBorder;
            row.getCell(2).value = `${defectElement.description}`;
            row.getCell(2).alignment = leftAlignment;
            row.getCell(2).font = {
              ...nameSize12Font,
              color: { argb: '000000' },
            };
            row.getCell(2).border = rightBorder;
            currentLine += 1;

            // break line between defects
            currentLine += 1;
          });
          // ruleElement.defects.forEach(defectHandler);

          // break line between rules
          currentLine += 1;
        }
      }
    }

    for (let i = 1; i < currentLine; i += 1) {
      this.getRow(i).height = 25;
    }

    await this.writeFile(outputPath);
  }

  generateRuleFile(data, outputPath) {
    const {
      ruleSetName,
      ruleName,
      ruleCode,
      total,
      defects,
      levelName,
      level,
    } = data;
    // construct excel
    this.addSheet('sheet1');
    // style
    const leftBorder = {
      top: { style: 'thin' },
      left: { style: 'thin' },
      bottom: { style: 'thin' },
    };
    const rightBorder = {
      top: { style: 'thin' },
      right: { style: 'thin' },
      bottom: { style: 'thin' },
    };
    const boldWhiteFont = {
      name: 'Arial',
      bold: true,
      size: 12,
      color: { argb: 'FFFFFF' },
    };
    const boldBlackFont = {
      name: 'Arial',
      bold: true,
      size: 12,
      color: { argb: '000000' },
    };
    const nameSize12Font = { name: 'Arial', size: 12 };
    const nameSize14Font = { name: 'Arial', size: 14 };
    const defaultFill = { type: 'pattern', pattern: 'solid' };
    const leftAlignment = { vertical: 'middle', horizontal: 'left', wrapText: true };
    const middleAlignment = { vertical: 'middle', horizontal: 'center' };
    this.lastSheet.getColumn(1).width = 20;
    this.lastSheet.getColumn(2).width = 60;
    this.lastSheet.properties.defaultRowHeight = 25;
    // rules content
    let currentLine = 1;
    this.mergeCells(`A${currentLine}`, `B${currentLine}`);
    let row = this.getRow(currentLine);
    row.getCell(1).value = `${ruleSetName} ${ruleCode}`;
    row.getCell(1).alignment = leftAlignment;
    row.getCell(1).font = {
      ...nameSize14Font,
      color: { argb: '000000' },
    };
    currentLine += 1;
    row = this.getRow(currentLine);
    row.getCell(1).value = `缺陷数量：${total}个`;
    row.getCell(1).alignment = leftAlignment;
    // level color
    const levelFill = {
      ...defaultFill,
    };
    if (level === 1) {
      levelFill.fgColor = { argb: 'cb3e36' };
    } else {
      levelFill.fgColor = {};
      levelFill.fgColor.argb = level === 3 ? '4dd5b3' : 'fdbb36';
    }
    row.getCell(1).fill = {
      ...defaultFill,
      fgColor: { argb: '87898b' },
    };
    row.getCell(1).font = boldWhiteFont;
    row.getCell(2).value = `${levelName}`;
    row.getCell(2).fill = levelFill;
    row.getCell(2).alignment = middleAlignment;
    row.getCell(2).font = boldWhiteFont;
    currentLine += 1;

    this.mergeCells(`A${currentLine}`, `B${currentLine}`);
    row = this.getRow(currentLine);
    // auto height
    const ruleDesc = `缺陷描述：${ruleName}`;
    row.height = Math.ceil(Buffer.byteLength(ruleDesc, 'utf8') / 95) * 25;
    row.getCell(1).value = ruleDesc;
    row.getCell(1).alignment = leftAlignment;
    row.getCell(1).fill = {
      ...defaultFill,
      fgColor: { argb: 'b9b8bb' },
    };
    row.getCell(1).font = boldBlackFont;
    currentLine += 2;
    defects.forEach((defectElement) => {
      row = this.getRow(currentLine);
      row.getCell(1).value = `缺陷${defectElement.index}`;
      row.getCell(1).alignment = leftAlignment;
      row.getCell(1).font = {
        ...nameSize14Font,
        bold: true,
        color: { argb: '000000' },
      };
      currentLine += 1;

      row = this.getRow(currentLine);
      row.getCell(1).value = '发生位置';
      row.getCell(1).alignment = leftAlignment;
      row.getCell(1).font = boldBlackFont;
      row.getCell(1).border = leftBorder;
      row.getCell(2).value = `${defectElement.filePath}`;
      row.getCell(2).alignment = leftAlignment;
      row.getCell(2).font = {
        ...nameSize12Font,
        color: { argb: '000000' },
      };
      row.getCell(2).border = rightBorder;
      currentLine += 1;

      row = this.getRow(currentLine);
      row.getCell(1).value = '起始位置';
      row.getCell(1).alignment = leftAlignment;
      row.getCell(1).font = boldBlackFont;
      row.getCell(1).border = leftBorder;
      row.getCell(2).value = `(${defectElement.locations.begin.line}, ${defectElement.locations.begin.column})`;
      row.getCell(2).alignment = leftAlignment;
      row.getCell(2).font = {
        ...nameSize12Font,
        color: { argb: '000000' },
      };
      row.getCell(2).border = rightBorder;
      currentLine += 1;

      row = this.getRow(currentLine);
      row.getCell(1).value = '终止位置';
      row.getCell(1).alignment = leftAlignment;
      row.getCell(1).font = boldBlackFont;
      row.getCell(1).border = leftBorder;
      row.getCell(2).value = `(${defectElement.locations.end.line}, ${defectElement.locations.end.column})`;
      row.getCell(2).alignment = leftAlignment;
      row.getCell(2).font = {
        ...nameSize12Font,
        color: { argb: '000000' },
      };
      row.getCell(2).border = rightBorder;
      currentLine += 1;

      // lines
      defectElement.lines.forEach((lineElement) => {
        row = this.getRow(currentLine);
        row.getCell(1).value = `${lineElement.line}`;
        row.getCell(1).alignment = middleAlignment;
        row.getCell(2).value = `${lineElement.content}`;
        row.getCell(2).alignment = leftAlignment;
        const lineFont = { ...nameSize12Font, color: { argb: '333333' } };
        if (lineElement.red) {
          lineFont.color.argb = 'fb0008';
          row.getCell(1).fill = {
            ...defaultFill,
            fgColor: { argb: 'e7e6e6' },
          };
          row.getCell(2).fill = {
            ...defaultFill,
            fgColor: { argb: 'e7e6e6' },
          };
        }
        row.getCell(1).font = lineFont;
        row.getCell(1).border = leftBorder;
        row.getCell(2).font = lineFont;
        row.getCell(2).border = rightBorder;
        currentLine += 1;
      });

      // status and description
      row = this.getRow(currentLine);
      row.getCell(1).value = '缺陷状态';
      row.getCell(1).alignment = leftAlignment;
      row.getCell(1).font = boldBlackFont;
      row.getCell(1).border = leftBorder;
      row.getCell(2).value = `${defectElement.status}`;
      row.getCell(2).alignment = leftAlignment;
      row.getCell(2).font = {
        ...nameSize12Font,
        color: { argb: '000000' },
      };
      row.getCell(2).border = rightBorder;
      currentLine += 1;

      row = this.getRow(currentLine);
      row.getCell(1).value = '信息说明';
      row.getCell(1).alignment = leftAlignment;
      row.getCell(1).font = boldBlackFont;
      row.getCell(1).border = leftBorder;
      row.getCell(2).value = `${defectElement.description}`;
      row.getCell(2).alignment = leftAlignment;
      row.getCell(2).font = {
        ...nameSize12Font,
        color: { argb: '000000' },
      };
      row.getCell(2).border = rightBorder;
      currentLine += 1;

      // break line between defects
      currentLine += 1;
    });

    this.writeFile(outputPath);
  }
}

module.exports = FileExcel;
